Skip to content

fix(swift-sdk): make Document transition contract/type pickers idb-drivable#3921

Merged
QuantumExplorer merged 1 commit into
v3.1-devfrom
claude/elastic-heisenberg-66d981
Jun 16, 2026
Merged

fix(swift-sdk): make Document transition contract/type pickers idb-drivable#3921
QuantumExplorer merged 1 commit into
v3.1-devfrom
claude/elastic-heisenberg-66d981

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Jun 16, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

The SwiftExampleApp Document state-transition builders (Purchase / Transfer / Update Price / Create / Replace / Delete) select their data contract and document type through SwiftUI Pickers that UI automation (idb) cannot drive. This blocked automating DOC-07 (Purchase Document) and every other contract-scoped document builder.

TransitionDetailView hosts these inputs in a ScrollView { VStack }, not a Form/List. In that host:

  • .accessibleInlinePicker renders as an opaque control that idb sees only as a Slider — the option rows are absent from the accessibility tree (describe-all and describe-point return nothing tappable).
  • .accessibleFormPicker / .pickerStyle(.navigationLink) renders and pushes its list, but silently drops the selection binding — navigationLink only commits its selection when it has a List/Form ancestor. (Verified on an iPhone 17 simulator: the row tap pops back but the checkmark stays on the previous value.)

So neither shared picker style works in this host, which is why the builders couldn't be driven.

What was done?

Replaced the contract and document-type pickers with an explicit NavigationLink to a small selection List whose rows are Buttons that write the binding directly and dismiss():

  • ContractSelectionList / DocumentTypeSelectionList in TransitionInputView.swift.
  • Each row carries a stable accessibilityIdentifiertransition.<input>.contractPicker.row.<idBase58> / transition.<input>.documentTypePicker.row.<name> — so idb can tap a specific contract/type by id, robustly across localization and layout changes.
  • Selection commits in any host (no Form/List dependency), and the trigger row shows the current selection. contractPicker() is shared by all six document builders, so all of them become drivable.

Also guarded TransitionDetailView's one-time form setup with a didInitializeForm flag: pushing a picker list re-fires .onAppear on pop-back, and re-running clearForm() there wiped the in-progress form (including the just-picked contract). Setup now runs only on first appearance; a freshly navigated builder is a new view instance and still resets correctly.

How Has This Been Tested?

Built the SwiftExampleApp for the simulator and drove DOC-07 end-to-end via idb on a booted iPhone 17 (testnet), using the existing fixture (contract 5jpKat9U82PGcfmeYm8QZZWX6q7zDo2C32PZMxHpbiGB, doc type card, Knight card Cdg8JTz6Rbx6Hq8swZLkVCLML3acRTtsShwVfrUpG2mX priced at 100000 credits, buyer qagaussqa ≠ owner):

  • Both pickers now push a real list with tappable, id-addressable rows.
  • Contract and document-type selections persist across the pop-back (clearForm guard).
  • The price auto-fetches (100000 credits) and the owner resolves — confirming the selections correctly drove the on-chain document/price lookup.

Note: Execute itself currently fails with a pre-existing, unrelated signing bugselectSigningKey (StateTransitionExtensions.swift) picks a CRITICAL TRANSFER key instead of an AUTHENTICATION key for document state transitions, so the platform rejects it (requires AUTHENTICATION). This affects all six document operations for identities that own a CRITICAL transfer key and is out of scope for this UI fix; it's tracked separately.

Breaking Changes

None. UI/testability change in the example app only; no protocol or public-API changes.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

Summary by CodeRabbit

Bug Fixes

  • Fixed an issue where form inputs were unexpectedly reset when navigating back from picker selections

New Features

  • Redesigned contract and document type selection interface with dedicated selection lists for improved navigation flow
  • Enhanced accessibility identifiers for better support with automated testing and accessibility tools

…ivable

The Document state-transition builders (Purchase / Transfer / Update Price /
Create / Replace / Delete) selected their contract and document type with
SwiftUI Pickers that UI automation (idb) cannot drive, which blocked
automating DOC-07 and the other contract-scoped document builders.

TransitionDetailView hosts these inputs in a ScrollView/VStack, not a
Form/List. In that host:
  - .accessibleInlinePicker renders as an opaque control idb sees only as a
    "Slider" (option rows absent from the accessibility tree), and
  - .accessibleFormPicker / .pickerStyle(.navigationLink) renders and pushes
    its list but silently drops the selection binding (it only commits with a
    List/Form ancestor).

Replace both pickers with an explicit NavigationLink to a small selection
List whose rows are Buttons that write the binding directly and dismiss().
Each row carries a stable accessibilityIdentifier
(transition.<input>.<picker>.row.<id>) so idb can tap a specific contract or
type reliably, and the selection commits in any host. contractPicker() is
shared by every document builder, so all of them become drivable.

Also guard TransitionDetailView's one-time form setup: pushing a picker list
re-fires .onAppear on pop-back, and re-running clearForm() there wiped the
in-progress form (including the just-picked contract). A didInitializeForm
flag runs clearForm()/pre-fill merge only on first appearance; a freshly
navigated builder is a new instance and still resets correctly.

Verified end-to-end on testnet via idb: the Purchase Document form drives
fully (contract "Contract with card", type "card", document id), selections
persist across pop-back, and the price auto-fetches (100000 credits).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5826bed1-acff-484b-a253-5638e9885952

📥 Commits

Reviewing files that changed from the base of the PR and between 160eb7c and 46f0acf.

📒 Files selected for processing (2)
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionInputView.swift

📝 Walkthrough

Walkthrough

TransitionDetailView gains a didInitializeForm state flag that gates .onAppear to run form setup only once, preventing resets when popping new navigation children. TransitionInputView replaces inline Picker controls for contract and document type selection with NavigationLink-presented ContractSelectionList and DocumentTypeSelectionList views that carry stable per-row accessibility identifiers.

Changes

Navigation picker refactor and onAppear guard

Layer / File(s) Summary
One-time form init guard
packages/swift-sdk/SwiftExampleApp/.../TransitionDetailView.swift
Adds @State var didInitializeForm: Bool and an early-return in .onAppear so clearForm() and initialInputs/initialCheckboxInputs merging run only on the first appearance.
NavigationLink-based contractPicker and documentTypePicker
packages/swift-sdk/SwiftExampleApp/.../TransitionInputView.swift
Removes inline Picker + .accessibleInlinePicker from both contractPicker() and documentTypePicker(), replacing each with a NavigationLink destination; selection callbacks and onSpecialAction notifications move into the row tap handlers.
ContractSelectionList and DocumentTypeSelectionList
packages/swift-sdk/SwiftExampleApp/.../TransitionInputView.swift
Adds two private SwiftUI views presenting List-based selection UIs with a none/select row, checkmark on current selection, binding updates, onSelect invocation, dismiss, and stable per-row accessibility identifiers.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • dashpay/platform#3903: Directly related — also modifies TransitionInputView's contract and document-type picker UI toward list-based NavigationLink selection with stable selection and accessibility handling.

Suggested reviewers

  • thepastaclaw
  • llbartekll
  • shumkov

🐇 Hoppity hop through the nav stack I go,
No more reset when I come back from below!
A little flag says "done, don't clear!"
My contracts and doc types remain right here.
Stable IDs for robots to find,
Leaving no stray clearForm() behind! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately captures the main change: making document transition pickers in the Swift SDK automatable via idb by replacing inline Picker controls with NavigationLink-driven selection lists.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/elastic-heisenberg-66d981

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@thepastaclaw

thepastaclaw commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

✅ Review complete (commit 46f0acf)

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Both agents and CodeRabbit converged on no in-scope findings. The PR is a focused SwiftExampleApp UI/testability fix that swaps inline Pickers for NavigationLink-pushed selection lists with stable per-row accessibility IDs, and guards TransitionDetailView's one-time form setup so popping the pushed picker doesn't wipe the in-progress form. The didInitializeForm guard is correctly scoped to the view-instance lifetime (transitionKey is a let, so a freshly-built builder is a new struct with a fresh @State). No consensus-critical surface area touched.

@QuantumExplorer
QuantumExplorer merged commit ceb8f52 into v3.1-dev Jun 16, 2026
18 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/elastic-heisenberg-66d981 branch June 16, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants